#ifndef MSGTIMER_H
#define MSGTIMER_H

#include <time.h>
#include "MsgModPC.h"
#include <map>

#if defined(_MSC_VER) || defined(_MSC_EXTENSIONS)
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64
#else
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
#endif

using std::map;

#define MSG_SET_TIMER 1100
#define MSG_DELETE_TIMER 1101
#define MSG_ON_TIMER 1101

bool operator < (struct timeval l, struct timeval r);
bool operator > (struct timeval l, struct timeval r);

class CMsgTimer : public CMsgModPC
{
public:
    struct timezone
    {
        int  tz_minuteswest; /* minutes W of Greenwich */
        int  tz_dsttime;     /* type of dst correction */
    };
    typedef struct
    {
        int time;
        int id;
    } T_TimerData;
    static int gettimeofday(struct timeval *tv, struct timezone *tz)
    {
        FILETIME ft;
        unsigned __int64 tmpres = 0;
        static int tzflag;

        if (NULL != tv)
        {
            GetSystemTimeAsFileTime(&ft);

            tmpres |= ft.dwHighDateTime;
            tmpres <<= 32;
            tmpres |= ft.dwLowDateTime;

            /*converting file time to unix epoch*/
            tmpres -= DELTA_EPOCH_IN_MICROSECS;
            tmpres /= 10;  /*convert into microseconds*/
            tv->tv_sec = (long)(tmpres / 1000000UL);
            tv->tv_usec = (long)(tmpres % 1000000UL);
        }

        if (NULL != tz)
        {
            if (!tzflag)
            {
                _tzset();
                tzflag++;
            }
            tz->tz_minuteswest = _timezone / 60;
            tz->tz_dsttime = _daylight;
        }

        return 0;
    }
    virtual void MOnTimeOut()
    {
        if (TimerList.size() == 0) return;
        list<T_Data>::iterator it = TimerList.begin();
        POST_MSG_TO(it->md, MSG_ON_TIMER, it->id, (char *)(0) );
        TimerMap[it->md].erase(it->id);
        TimerList.erase(it);
        SetTime();
    }
    virtual void MOnRecvMsg(unsigned int type, T_LParameter lp, const DataFlow &data)
    {
        T_TimerData timer;
        if ( data.CopyData(&timer, sizeof(T_TimerData)) == sizeof(T_TimerData) )
        {
            list<T_Data>::iterator it;
            T_Data tdata;

            switch (type)
            {
            case MSG_SET_TIMER:
                if (timer.time <= 0) return;
                if (TimerMap[lp].find(timer.id) == TimerMap[lp].end())
                {
                    tdata.id = timer.id;
					tdata.md = lp;

                    tdata.time = timer.time;
					gettimeofday( &tdata.expire, NULL );
					tdata.expire.tv_sec += timer.time / 1000;
					tdata.expire.tv_usec += (timer.time % 1000) * 1000;
                    for (it = TimerList.begin(); it != TimerList.end(); it++)
                    {
                        if (it->expire > tdata.expire)
                            break;
                    }
                    it = TimerList.insert(it, tdata);
                    TimerMap[lp][timer.id] = it;
                }
                else
                {
                    it = TimerMap[lp][timer.id];
                    tdata = *it;

					tdata.time = timer.time;
					gettimeofday( &tdata.expire, NULL );
					tdata.expire.tv_sec += timer.time / 1000;
					tdata.expire.tv_usec += (timer.time % 1000) * 1000;                    
                    TimerList.erase(it);
                    for (it = TimerList.begin(); it != TimerList.end(); it++)
                    {
                        if (it->expire > tdata.expire)
                            break;
                    }
                    it = TimerList.insert(it, tdata);
                    TimerMap[lp][timer.id] = it;
                }
                SetTime();
                break;
            case MSG_DELETE_TIMER:
                if (TimerMap[lp].find(timer.id) != TimerMap[lp].end())
                {
                    it = TimerMap[lp][timer.id];
                    TimerList.erase(it);
                    TimerMap[lp].erase(timer.id);
                    SetTime();
                }
                break;
            }
        }

    }
private:
	void SetTime()
	{
		struct timeval t;
		gettimeofday( &t, NULL );
		
        if (TimerList.size() > 0)
		{
			if ( TimerList.begin()->expire < t ) return MOnTimeOut();
			SetSleepTime( (TimerList.begin()->expire.tv_sec - t.tv_sec) * 1000
							+ (TimerList.begin()->expire.tv_usec - t.tv_usec) / 1000 );
		}
        else
            SetSleepTime(0);
	}
    typedef struct
    {
        T_ModuleDescriptor md;
		struct timeval expire;
        int time;
        int id;
    } T_Data;
    list<T_Data> TimerList;
    map<T_ModuleDescriptor, map<int, list<T_Data>::iterator> >  TimerMap;
};




CMsgTimer *GetMsgTimer();

#define SetTimer(a) GetMsgTimer()->MPostMsg(MSG_SET_TIMER, GetMD(), a)
#define DelTimer(a) GetMsgTimer()->MPostMsg(MSG_DELETE_TIMER, GetMD(), a)











#endif